<?php
class PortalWebServiceDataBase{
	protected $server_config;
	protected $timeless;
	protected $time_now;
	protected $search;

	public function __construct($config, $timeless, $time_now) {
		$this->server_config = $config;
		$this->timeless      = $timeless;
		$this->time_shift    = $time_now;
		$this->search = new SearchClientWS();
	}

	protected function getDataById($table,$id){
		$table  = $this->__check_table($table);
		$id     = $this->__check_int($id,'id');
		$rs = $this->search->query($table,"id:$id");
		if($rs->response->numFound){
			return $rs->response->docs[0];
		}else{
			return null;
		}
	}
	protected function getFormatDataById($table,$id,$lang='zh',$format='json'){
		$lang   = $this->__check_lang($lang);
		$format = $this->__check_format($format);

		$data = $this->getDataById($table,$id);
		if(empty($data)) return null;
		$rs = call_user_func_array(array($this,"make{$table}Data"),array($data,$lang));
		if(empty($rs))   return null;

		return ($format=='xml' ? CommonUtils::arrayToXml($rs) : $rs);
	}
	protected function getDataByQuery($table,$query,$offset=0,$limit=10,array $sort=array(), $extra = array(), $raw = false ) {
		$table  = $this->__check_table($table);
		$offset = $this->__check_int($offset,'offset');
		$limit  = $this->__check_int($limit,'limit');
		$sort   = $this->__check_sort_key($table,$sort);
		$rs = $this->search->query($table,$query,$offset,$limit,$sort, $extra, $raw) ;
		if ( !empty ( $extra) || $raw ) return $rs ;
		if (!is_object($rs)) return null;
		if($rs->response->numFound) {
			return $rs->response;
		}else{
			return null;
		}
	}
	protected function getFormatDataByQuery($table,$query,$offset=0,$limit=10,array $sort=array(),$lang='zh',$format='json'){
		$lang   = $this->__check_lang($lang);
		$format = $this->__check_format($format);

		$rs = $this->getDataByQuery($table,$query,$offset,$limit,$sort) ;
		$data = array('total'=>0,'size'=>0,'offset' => $offset,'limit' => $limit,'sort' => $sort,'data'=>array());

		if(empty($rs)) return $data;

		$data['total'] = $rs->numFound;
		$data['size']  = count($rs->docs);

		foreach($rs->docs as $row){
			$data['data'][$row->id] = call_user_func_array(array($this,"make{$table}Data"),array($row,$lang));
		}
		if ($table == 'Video') file_put_contents('/tmp/Video.html', var_export($data,true));
		return ($format=='xml' ? CommonUtils::arrayToXml($data) : $data);
	}

	protected function __check_sort_key($table,$sort_array,$exclude=array('favour','view')){
		if(empty($sort_array)) return array();
		# cache #####
		$mc_handle = new Memcache();
		foreach ($this->server_config->memcache->farm as $v) {
			$v = (array) $v;
			$mc_handle->addServer($v['server'], $v['port']);
		}
		$cache_key = 'MyTv+PortalWS:'.$this->timeless.':'.$table.':fields';

		$fields = @$mc_handle->get($cache_key);
		if(!$fields){
			$one_data = $this->getDataByQuery($table,'id:*',0,1);
			if(empty($one_data->numFound) || $one_data->numFound<1){
				throw new PortalWebServiceException('sort',PortalWebServiceException::PARAMETERS_ERROR);
			}
			$fields = array_keys(get_object_vars($one_data->docs[0]));
			$mc_handle->set($cache_key, $fields, 0, (int)$this->server_config->memcache->cache_time);
		}
		# cache #####

		$sort = array();
		if(!is_array($sort_array)) $sort_array = array($sort_array);

		foreach($sort_array as $key=>$value){
			if(is_numeric($key)){
				$key = $value; 
				$value = 'asc';
			}
			$key   = strtolower($key);
			$value = strtolower($value);
			if(!in_array($key,$exclude) && (!in_array($key,$fields) || !in_array($value,array('desc','asc')))){
				throw new PortalWebServiceException('sort',PortalWebServiceException::PARAMETERS_ERROR);
			}
			$sort[$key] = $value;
		}
		return $sort;
	}


	protected function __check_table($table){
		$table = strtolower($table);
		$tables = array(
			'cast'=>'Cast',
			'category'=>'Category',
			'channel'=>'Channel',
			'chapter'=>'Chapter',
			'episode'=>'Episode',
			'folder'=>'Folder',
			'folderimage'=>'FolderImage',
			'foldervideo'=>'FolderVideo',
			'image'=>'Image',
			'info'=>'Info',
			'programme'=>'Programme',
			'video'=>'Video',
			'chaptervideoepisode' => 'ChapterVideoEpisode',
		);
		if(!array_key_exists($table, $tables)){
			throw new PortalWebServiceException($table,PortalWebServiceException::PARAMETERS_ERROR);
		}
		return $tables[$table];
	}

	protected function makeCategoryData($data,$lang){
		return array(
			'id'=>$data->id,
			'parent_id'=>$data->parent_id,
			'path'=>$data->path,
			'title'=>( ($data->{"title_$lang"}) ? ($data->{"title_$lang"}) : $data->title),
			'forum_id'=>(property_exists($data, 'forum_id'))?$data->forum_id:null,
		);
	}

	public function _getProgrammeIdByVideoId($video_id){
		$rs = $this->search->query('Video',"id:$video_id");
		if($rs->response->numFound){
			return $rs->response->docs[0]->programme_id;
		}else{
			return 0;
		}
	}
	public function _getCategoryIdByPath($category_path){
		$rs = $this->search->query('Category',"path:$category_path AND parent_id:0");
		if(empty($rs->response->numFound) || $rs->response->numFound>1){
			return '\-1';
		}
		return $rs->response->docs[0]->id;
	}

	public function _getVideoByEpisodeId($id,$lang='zh',$format='json'){
		$id     = $this->__check_int($id,'episode_id');
		$lang   = $this->__check_lang($lang);
		$format = $this->__check_format($format);
		$rs = $this->search->query('Video',"episode_id:$id");
		if(empty($rs->response->numFound)) return null;
		$data = $this->makeVideoData($rs->response->docs[0],$lang);	
		return ($format=='xml' ? CommonUtils::arrayToXml($data) : $data);
	}


	public function _getProgrammeIdsByCategoryPath($category_path){
		$programmes = array();
		$query = 'primary_category_id:'.$this->_getCategoryIdByPath($category_path);
		$rs = $this->search->query('Programme',$query,0,999999999);

		if(isset($rs->response->docs)){
			foreach($rs->response->docs as $row){
				$programmes[] = $row->id;
			}
		}
		if($programmes) return $programmes;
		else return array('\-1');
	}


	protected function makeFolderData($data,$lang){
		$folder = array(
			'id' => $data->id,
			'type'=>$data->folder_type_path,
			'title'=>( ($data->{"title_$lang"}) ? ($data->{"title_$lang"}) : $data->title),
			'contains'=>$data->contains,
			'items' => array()
		);
		$contains  = trim($data->contains);
		$item_data = $this->getDataByQuery('folder'.$contains,'folder_id:'.$data->id,0,999999999);
		if($item_data){
			foreach($item_data->docs as $item){
				$folder['items'][$item->id]=$item;
			}
		}
		return $folder;
	}

	protected function makeChapterVideoEpisodeData ( $data, $lang ) {
		return array (
			"programme_title_zh" => $data->programme_title_zh,
			"in_time" => $data->in_time,
			"mytv_plus_view" => $data->mytv_plus_view,
			"chapter_id" => $data->chapter_id,
			"on_air_date" => $data->on_air_date,
			"modified_date" => $data->modified_date,
			"chapter_title_zh" => $data->chapter_title_zh,
			"programme_title_en" => $data->programme_title_en,
			"episode_title_zh" => $data->episode_title_zh,
			"episode_no" => $data->episode_no,
			"id" => $data->id,
			"online_time" => $data->online_time,
			"last_modified"=> $data->last_modified,
			"video_title_zh"=> $data->video_title_zh,
			"video_id"=> $data->video_id,
			"chapter_title_en"=> $data->chapter_title_en,
			"tags"=> $data->tags,
			"episode_title_en"=> $data->episode_title_en,
			"video_type"=> $data->video_type,
			"episode_id"=> $data->episode_id,
			"video_title_en"=> $data->video_title_en,
			"description_en"=> $data->description_en,
			"created_datetime"=> $data->created_datetime,
			"categories"=> $data->categories,
			"description_zh"=> $data->description_zh,
			"programme_id"=> $data->programme_id
		);
	}

	protected function makeProgrammeData($data,$lang){
		$category_list = array();
		if($data->category_list){
			$str = trim(str_replace(',',' ',$data->category_list));
			if($str){
				$rs = $this->getDataByQuery('Category',"id:($str)",0,999999999);
				if($rs){
					foreach($rs->docs as $one){
						$category_list[$one->id] = $this->makeCategoryData($one,$lang);
					}
				}
			}
		}
		return array(
			'id'=>  $data->id ,
			'primary_category_id'=>  $data->primary_category_id ,
			'meta_keywords'=>  $data->meta_keywords ,
			'meta_description'=>  $data->meta_description ,
			'forum_id'=>  $data->forum_id ,
			'number_of_episodes'=>  $data->number_of_episodes ,
			'total_view' => (property_exists($data, 'total_view'))?$data->total_view:0,
			'total_favour' => (property_exists($data, 'total_fav'))?$data->total_fav:0,
			'casts'=>  $data->casts,
			'tags'=>  $data->tags ,
			'path'=>  $data->path ,
			'starting_episode_no'=>  $data->starting_episode_no ,
			'nominal_duration'=>  $data->nominal_duration ,
			'first_network_code'=>  $data->first_network_codes ,
			'production_start_date'=>  $data->production_start_date ,
			'blog_url'=>  $data->blog_url ,
			'created_at'=>  $data->created_at ,
			'online_time'=>  $data->online_time ,
			'offline_time'=>  $data->offline_time ,
			'first_episode_time_onair' => $data->first_episode_time_onair,
			'last_episode_time_onair' => $data->last_episode_time_onair,
			'modified_at' => $data->modified_at , 

			'video_type' => $data->video_type,
			'premium_title' => ( ($data->{"premium_title_$lang"}) ? ($data->{"premium_title_$lang"}) : $data->premium_title),
			'ppv_flag' => $data->ppv_flag,
			'ppv_online_time' => $data->ppv_online_time,
			'ppv_offline_time' => $data->ppv_offline_time,
			'ppv_country_allow_list' => $data->ppv_country_allow_list,
			'ppv_country_deny_list' => $data->ppv_country_deny_list,
			'subscription_flag' => $data->subscription_flag,
			'subscription_free_flag' => $data->subscription_free_flag,
			'subscription_online_time' => $data->subscription_online_time,
			'subscription_offline_time' => $data->subscription_offline_time,
			'subscription_country_allow_list' => $data->subscription_country_allow_list,
			'subscription_country_deny_list' => $data->subscription_country_deny_list,

			'title'=>( ($data->{"title_$lang"}) ? ($data->{"title_$lang"}) : $data->title),
			'description'=>( ($data->{"description_$lang"}) ? ($data->{"description_$lang"}) : $data->description) ,
			'channelInfoPremiere'=>( ($data->{"first_onair_information_$lang"}) ? ($data->{"first_onair_information_$lang"}) : $data->first_onair_information) ,
			'fact_background'=>( ($data->{"fact_background_$lang"}) ? ($data->{"fact_background_$lang"}) : $data->fact_background) ,
			'banner_image' =>  $data->banner_image ,
			'key_art_image' =>  $data->key_art_image ,
			'first_time_onair'=>  $data->first_episode_time_onair ,
			'objective'=>  $data->objective ,
			'category' =>  $category_list ,
		);
	}

	protected function makeInfoData( $data, $lang ) {
		return array(
			"offline_time" => $data->offline_time,
			"chapter_id" => $data->chapter_id,
			"premium_title" => $data->premium_title,
			"ppv_offline_time" => $data->premium_title,
			"premium_title_zh" => $data->premium_title_zh,
			"online_time" => $data->online_time,
			"id" => $data->id,
			"info_type_id" => $data->info_type_id,
			"last_modified" => $data->last_modified,
			"title" => $data->title,
			"onair_episode_no" => $data->onair_episode_no,
			"ppv_online_time" => $data->ppv_online_time,
			"ppv_country_allow_list" => $data->ppv_country_allow_list,
			"description" => $data->description,
			"extras" => json_decode($data->extras, true),
			"created_at" => $data->created_at,
			"subscription_offline_time" => $data->subscription_offline_time,
			"video_id" => $data->video_id,
			"ppv_country_deny_list" => $data->ppv_country_deny_list,
			"ppv_flag" => $data->ppv_flag,
			"subscription_country_deny_list" => $data->subscription_country_deny_list,
			"subscription_country_allow_list" => $data->subscription_country_allow_list,
			"subscription_flag" => $data->subscription_flag,
			"video_type" => $data->video_type,
			"episode_id" => $data->episode_id,
			"info_id" => $data->info_id,
			"subscription_online_time" => $data->subscription_online_time,
			"subscription_free_flag" => $data->subscription_free_flag,
			"premium_title_en" => $data->premium_title_en,
			"modified_at" => $data->modified_at,
			"programme_id" => $data->programme_id,
		);
	}

	protected function makeVideoData($data,$lang){
		$programme_data = $this->getDataById('Programme',$data->programme_id);
		return array(
			'id' => $data->id,
			'title'=>( ($data->{"title_$lang"}) ? ($data->{"title_$lang"}) : $data->title),
			'other_videos'=> $data->other_videos,
			'episode_id' => $data->episode_id,
			'programme_id' => $data->programme_id,
			'mytv_plus_view' => (property_exists($data, 'mytv_plus_view'))?$data->mytv_plus_view:0,
			'video_type' => $data->video_type,
			'breakpoint'=> $data->breakpoint,
			'duration'=> $data->duration,
			'total_view' => (property_exists($data, 'total_view'))?$data->total_view:0,
			'total_favour' => (property_exists($data, 'total_fav'))?$data->total_fav:0,
			#'folder_list'=> $data->folder_list,
			#'first_time_onair'=> $programme_data->first_time_onair,
			'first_time_onair'=> $data->first_time_onair,
			'onair_episode_no' => $data->onair_episode_no,
			'online_time'=> $data->online_time,
			'offline_time'=> $data->offline_time,
			'folder_type_path' => $data->folder_type_path,
			'video_type' => $data->video_type,
			'premium_title' => ( ($data->{"premium_title_$lang"}) ? ($data->{"premium_title_$lang"}) : $data->premium_title),
			'ppv_flag' => $data->ppv_flag,
			'ppv_online_time' => $data->ppv_online_time,
			'ppv_offline_time' => $data->ppv_offline_time,
			'ppv_country_allow_list' => $data->ppv_country_allow_list,
			'ppv_country_deny_list' => $data->ppv_country_deny_list,
			'subscription_flag' => $data->subscription_flag,
			'subscription_free_flag' => $data->subscription_free_flag,
			'subscription_online_time' => $data->subscription_online_time,
			'subscription_offline_time' => $data->subscription_offline_time,
			'subscription_country_allow_list' => $data->subscription_country_allow_list,
			'subscription_country_deny_list' => $data->subscription_country_deny_list,

			'tags'=> $data->tags,
			'country_allow_list'=> $data->country_allow_list,
			'country_deny_list'=> $data->country_deny_list,
			'created_at'=> $data->created_at,
			'modified_at'=> $data->modified_at,
			'vi_data' => $data->vi_data,
			'ii_data' => $data->ii_data,
		);
	}


	protected function makeEpisodeData($data,$lang){
		$video_data = $this->_getVideoByEpisodeId($data->id);
		if(empty($video_data)){
			$video_data = array(
				'other_videos'=> '',
				'breakpoint'=> '',
				'duration'=> '',
				'online_time'=> '',
				'offline_time'=> '',
				'tags'=> '',
			);
		}
		return array(
			'id'=> $data->id,
			'title'=>( ($data->{"title_$lang"}) ? ($data->{"title_$lang"}) : $data->title),
			'description'=>( ($data->{"description_$lang"}) ? ($data->{"description_$lang"}) : $data->description) ,
			'description_short'=>( ($data->{"description_short_$lang"}) ? ($data->{"description_short_$lang"}) : $data->description_short),
			'onair_episode_no' => $data->onair_episode_no,
			'other_videos'=> $video_data['other_videos'],
			'breakpoint'=> $video_data['breakpoint'],
			'duration'=> $video_data['duration'],
			'online_time'=> $data->online_time,
			'offline_time'=> $data->offline_time,

			'video_type' => $data->video_type,
			'premium_title' => ( ($data->{"premium_title_$lang"}) ? ($data->{"premium_title_$lang"}) : $data->premium_title),
			'ppv_flag' => $data->ppv_flag,
			'ppv_online_time' => $data->ppv_online_time,
			'ppv_offline_time' => $data->ppv_offline_time,
			'ppv_country_allow_list' => $data->ppv_country_allow_list,
			'ppv_country_deny_list' => $data->ppv_country_deny_list,
			'subscription_flag' => $data->subscription_flag,
			'subscription_free_flag' => $data->subscription_free_flag,
			'subscription_online_time' => $data->subscription_online_time,
			'subscription_offline_time' => $data->subscription_offline_time,
			'subscription_country_allow_list' => $data->subscription_country_allow_list,
			'subscription_country_deny_list' => $data->subscription_country_deny_list,

			'tags'=> $video_data['tags'],
			'created_at'=> $data->created_at,
			'modified_at'=> $data->modified_at,
		);
	}

	protected function makeChapterData($data,$lang){
		$video_data = $this->getDataById('Video',$data->video_id);
		return array(
			'id'=> $data->id,
			'programme_id'=> $data->programme_id,
			'episode_id'=> $data->episode_id,
			'video_id'=> $data->video_id,
			'ii_data' => $data->ii_data,
			'title'=>( ($data->{"title_$lang"}) ? ($data->{"title_$lang"}) : $data->title),
			'description'=>( ($data->{"description_$lang"}) ? ($data->{"description_$lang"}) : $data->description) ,
			'tags'=>json_decode($data->tags,1),
			'modified_at'=> $data->modified_at,
			'infos'=> $data->infos,
			'in_time' => $data->in_time,
			'out_time' => $data->out_time,
			'online_time'=>  $video_data->online_time,
			'offline_time'=> $video_data->offline_time,

			'video_type' => $data->video_type,
			'premium_title' => ( ($data->{"premium_title_$lang"}) ? ($data->{"premium_title_$lang"}) : $data->premium_title),
			'ppv_flag' => $data->ppv_flag,
			'ppv_online_time' => $data->ppv_online_time,
			'ppv_offline_time' => $data->ppv_offline_time,
			'ppv_country_allow_list' => $data->ppv_country_allow_list,
			'ppv_country_deny_list' => $data->ppv_country_deny_list,
			'subscription_flag' => $data->subscription_flag,
			'subscription_free_flag' => $data->subscription_free_flag,
			'subscription_online_time' => $data->subscription_online_time,
			'subscription_offline_time' => $data->subscription_offline_time,
			'subscription_country_allow_list' => $data->subscription_country_allow_list,
			'subscription_country_deny_list' => $data->subscription_country_deny_list,

			'casts'=> $data->casts,
			'created_at'=> $data->created_at,
			'categories'=> $data->categories,
		);
	}

	protected function makeOneData ( $data, $lang ) {
		return array ( 
			"id" => $data->id,
			"programme_title" => $data->{"programme_title_$lang"},
			"in_time" => $data->$in_time,
			"mytv_plus_view" => $data->$mytv_plus_view,
			"chapter_id" => $data->chapter_id ,
			"on_air_date" => $data->on_air_date,
			"modified_date" => $data->modified_date,
			"chapter_title" => $data->{"chapter_title_$lang"},
			"episode_title_zh" => $data->{"episode_title_$lang"},
			"episode_no" => $data->$episode_no,
			"online_time" => $data->online_time,
			"last_modified" => $data->last_modified,
			"video_title" => $data->{"video_title_$lang"},
			"video_id" => $data->video_id ,
			"tags" => $data->tags,
			"video_type" => $data->video_type,
			"episode_id" => $data->episode_id,
			"video_title_en" => $data->video_title_en,
			"description_en" => $data->description_en,
			"created_datetime" => $data->created_datetime,
			"categories" => $data->categories,
			"description_zh" => $data->description_zh,
			"programme_id" => $data->programme_id
		) ;
	}

	protected function __check_lang($lang){
		$lang = strtolower(trim($lang));
		if(!in_array($lang,array('en','zh','gb'))){
			throw new PortalWebServiceException('lang',PortalWebServiceException::PARAMETERS_ERROR);
		}
		return ($lang=='gb' ? 'zh' : $lang);
	}
	protected function __check_format($format){
		$format = strtolower(trim($format));
		if(!in_array($format,array('json','xml'))){
			throw new PortalWebServiceException('format',PortalWebServiceException::PARAMETERS_ERROR);
		}
		return $format;
	}
	protected function __check_int($val,$name){
		if(!preg_match('/^\d*(_\d*)?$/',$val)) throw new PortalWebServiceException($name,PortalWebServiceException::PARAMETERS_ERROR);
		return $val;
	}
	protected function __check_datetime($datetime,$name){
		if(is_numeric($datetime) && strlen($datetime) == 10){
			return $datetime;
		}else{
			$time = strtotime($datetime);
			if(false === $time){
				throw new PortalWebServiceException($name,PortalWebServiceException::PARAMETERS_ERROR);
			}
			return $time;
		}
	}

	public function _functionlist($format='json'){
		$class = new ReflectionClass($this);
		$funcs = $class->getMethods();
		$list  = array();
		foreach($funcs as $fun){
			if($fun->isPublic() && preg_match('/^_[a-z]/i',$fun->getName()) && $fun->getDeclaringClass() == $class){
				$fun_name = substr($fun->getName(),1);
				$list[$fun_name] = array();
				$params = $fun->getParameters();
				foreach($params as $param){
					$list[$fun_name][$param->getName()] = array(
						'isArray'=>$param->isArray(),
						'allowsNull'=>$param->allowsNull(),
						'isPassedByReference'=>$param->isPassedByReference(),
						'isOptional'=>$param->isOptional(),
						'isDefaultValueAvailable'=>$param->isDefaultValueAvailable(),
					);
					if($param->isDefaultValueAvailable()){
						$list[$fun_name][$param->getName()]['defaultValue'] = $param->getDefaultValue();
					}
				}
			}
		}
		return $list;
	}
}
